package com.naughty.shopapi.controller;

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.naughty.shopapi.handler.MD5Handler;
import com.naughty.shopapi.mapper.UsersMapper;
import com.naughty.shopapi.pojo.RegisterErrors;
import com.naughty.shopapi.pojo.TokenVO;
import com.naughty.shopapi.pojo.Users;
import com.naughty.shopapi.utils.FileUtil;
import com.naughty.shopapi.utils.JWTUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static com.naughty.shopapi.utils.JWTUtil.isExpiration;
import static com.naughty.shopapi.utils.JWTUtil.refreshToken;

@Api(tags = "用户相关操作")
@RestController
@RequestMapping("api")
public class UsersController {

    @Autowired
    private UsersMapper usersMapper;

    private static Pattern pattern; //Pattern是用于编译正则表达式
    private static Matcher matcher; //Matcher用于匹配正则表达式

    /**
     * 获取用户信息
     *
     * @return
     */
    @ApiOperation("获取用户信息")
    @GetMapping("/user")
    public ResponseEntity<Object> getUser() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        final String Authorization = request.getHeader("authorization");
        String[] tokens = Authorization.split(" ");
        String token = tokens[1];
        final HashMap<String, Object> tokenMap = new HashMap<>();
        tokenMap.put("remember_token", token);
        final List<Users> isToken = usersMapper.selectByMap(tokenMap);
        if (isToken.size() == 0) {
            final RegisterErrors registerErrors = new RegisterErrors();
            registerErrors.setMessage("The token has been blacklisted.");
            registerErrors.setErrors("Token已被列入黑名单");
            registerErrors.setStatus_code(401);
            return new ResponseEntity<>(registerErrors, HttpStatus.UNAUTHORIZED);
        } else {
            if (!isExpiration(token)) {//判断token有效期
                return new ResponseEntity<>(isToken, HttpStatus.OK);
            } else {
                final RegisterErrors registerErrors = new RegisterErrors();
                registerErrors.setMessage("Token Signature could not be verified.");
                registerErrors.setErrors("Token已失效");
                registerErrors.setStatus_code(401);
                return new ResponseEntity<>(registerErrors, HttpStatus.UNAUTHORIZED);
            }
        }
    }

    /**
     * 修改用户名
     *
     * @param name name参数
     * @return
     */
    @ApiOperation("修改用户名")
    @PutMapping("/user")
    public ResponseEntity<Object> updateUser(@RequestParam String name) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        final String Authorization = request.getHeader("authorization");
        String[] tokens = Authorization.split(" ");
        String token = tokens[1];
        final HashMap<String, Object> tokenMap = new HashMap<>();
        tokenMap.put("remember_token", token);
        final List<Users> isToken = usersMapper.selectByMap(tokenMap);
        if (isToken.size() == 0) {
            final RegisterErrors registerErrors = new RegisterErrors();
            registerErrors.setMessage("The token has been blacklisted.");
            registerErrors.setErrors("Token已被列入黑名单");
            registerErrors.setStatus_code(401);
            return new ResponseEntity<>(registerErrors, HttpStatus.UNAUTHORIZED);
        } else {
            if (!isExpiration(token)) {//判断token有效期
                UpdateWrapper<Users> updateWrapper = new UpdateWrapper<>();
                updateWrapper.eq("email", isToken.get(0).getEmail()).set("name", name);
                usersMapper.update(null, updateWrapper);
                return new ResponseEntity<>(null, HttpStatus.NO_CONTENT);
            } else {
                final RegisterErrors registerErrors = new RegisterErrors();
                registerErrors.setMessage("Token Signature could not be verified.");
                registerErrors.setErrors("Token已失效");
                registerErrors.setStatus_code(401);
                return new ResponseEntity<>(registerErrors, HttpStatus.UNAUTHORIZED);
            }
        }
    }

    /**
     * 修改用户密码
     * 判断token是否是用户当前登录的token
     * 判断token是否在有效期内
     * 判断用户传参条件是否都符合范围
     * 修改数据库
     *
     * @param old_password
     * @param password
     * @param password_confirmation
     * @return
     */
    @ApiOperation("更新用户密码")
    @PostMapping("/auth/password/update")
    public ResponseEntity<Object> updatePassword(
            @RequestParam String old_password,
            @RequestParam String password,
            @RequestParam String password_confirmation
    ) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        final String Authorization = request.getHeader("authorization");
        String[] tokens = Authorization.split(" ");
        String token = tokens[1];
        final HashMap<String, Object> tokenMap = new HashMap<>();
        tokenMap.put("remember_token", token);
        final List<Users> isToken = usersMapper.selectByMap(tokenMap);
        if (isToken.size() == 0) {//传入token与用户token
            final RegisterErrors registerErrors = new RegisterErrors();
            registerErrors.setMessage("The token has been blacklisted.");
            registerErrors.setErrors("Token已被列入黑名单");
            registerErrors.setStatus_code(401);
            return new ResponseEntity<>(registerErrors, HttpStatus.UNAUTHORIZED);
        } else {

            if (!isExpiration(token)) {//判断token有效期
                final RegisterErrors registerErrors = new RegisterErrors();
                final HashMap<String, Object> errormsg = new HashMap<>();
                final ArrayList<Object> oldPasswordMsg = new ArrayList<>();
                final ArrayList<Object> passwordMsg = new ArrayList<>();

                Boolean oldPasswordBoo = false, passwordBoo = false; //必填条件判断状态

                /**
                 * 参数条件：
                 * old_password：非空、不少于6个字符、不大于16个字符、匹配旧密码
                 * password：非空(只判断password)，至少6字符，限定16字符，判断二次输入是否相同(比较两次输入)
                 */
                if (old_password.equals("")) {//old_password 条件
                    oldPasswordMsg.add("旧密码 不能为空");
                    errormsg.put("old_password", oldPasswordMsg);
                } else {
                    if (old_password.length() < 6) {
                        oldPasswordMsg.add("旧密码 至少为 6 个字符");
                        errormsg.put("old_password", oldPasswordMsg);
                    } else {
                        if (old_password.length() >= 16) {
                            oldPasswordMsg.add("旧密码 不能大于 16 个字符");
                            errormsg.put("old_password", oldPasswordMsg);
                        } else {
                            //匹配旧密码
                            final HashMap<String, Object> oldPWMap = new HashMap<>();
                            oldPWMap.put("email", isToken.get(0).getEmail());
                            oldPWMap.put("password", MD5Handler.stringToMD5(old_password));
                            final List<Users> users = usersMapper.selectByMap(oldPWMap);
                            if (users.size() == 0) {
                                oldPasswordMsg.add("旧密码不正确");
                                errormsg.put("old_password", oldPasswordMsg);
                            } else {
                                oldPasswordBoo = true;
                            }
                        }
                    }
                }
                if (password.equals("")) {//password 条件
                    passwordMsg.add("密码 不能为空");
                    errormsg.put("password", passwordMsg);
                } else {
                    if (password.length() < 6) {
                        passwordMsg.add("密码 至少为 6 个字符");
                    }
                    if (password.length() >= 16) {
                        passwordMsg.add("密码 不能大于 16 个字符");
                    }
                    if (password.equals(password_confirmation)) {
                        //密码一致后注册操作
                        passwordBoo = true;
                    } else {
                        passwordMsg.add("密码 两次输入不一致");
                        errormsg.put("password", passwordMsg);
                    }
                }
                if (oldPasswordBoo && passwordBoo) {
                    //密码重新赋值操作
                    UpdateWrapper<Users> updateWrapper = new UpdateWrapper<>();
                    updateWrapper.eq("email", isToken.get(0).getEmail()).set("password", MD5Handler.stringToMD5(password));
                    usersMapper.update(null, updateWrapper);
                    return new ResponseEntity<>(null, HttpStatus.NO_CONTENT);
                } else {
                    registerErrors.setMessage("The given data was invalid.");
                    registerErrors.setErrors(errormsg);
                    registerErrors.setStatus_code(422);
                    return new ResponseEntity<>(registerErrors, HttpStatus.UNPROCESSABLE_ENTITY);
                }

            } else {
                final RegisterErrors registerErrors = new RegisterErrors();
                registerErrors.setMessage("Token Signature could not be verified.");
                registerErrors.setErrors("Token已失效");
                registerErrors.setStatus_code(401);
                return new ResponseEntity<>(registerErrors, HttpStatus.UNAUTHORIZED);
            }
        }
    }

    /**
     * 用户注册
     *
     * @param name                  昵称
     * @param email                 邮箱
     * @param password              密码
     * @param password_confirmation 确认密码
     * @param openid                微信公众平台openid，小程序注册使用
     * @param avatar                用户头像
     * @return 状态码 201 创建成功，状态码 422 参数错误
     */
    @ApiOperation("用户注册")
    @PostMapping("/auth/register")//ResponseEntity是通用类型，因此可以使用任意类型作为响应体。
    public ResponseEntity<Object> register(
            @RequestParam String name,
            @RequestParam String email,
            @RequestParam String password,
            @RequestParam(required = false) String password_confirmation,
            @RequestParam(required = false) String openid,
            @RequestParam(required = false) String avatar
    ) {
        final RegisterErrors registerErrors = new RegisterErrors();
        final HashMap<String, Object> errormsg = new HashMap<>();
        final ArrayList<Object> nameMsg = new ArrayList<>();
        final ArrayList<Object> emailMsg = new ArrayList<>();
        final ArrayList<Object> passwordMsg = new ArrayList<>();
        final ArrayList<Object> openidMsg = new ArrayList<>(); //条件不明确---未定义
        final ArrayList<Object> avatarMsg = new ArrayList<>();

        Boolean nameBoo = false, emailBoo = false, passwordBoo = false; //必填条件判断状态
        String mailRegex, mailName, mailDomain;
        mailName = "^[0-9a-z]+\\w*";       // ^表明一行以什么开头；^[0-9a-z]表明要以数字或小写字母开头；\\w*表明匹配任意个大写小写字母或数字或下划线；
        mailDomain = "([0-9a-z]+\\.)+[0-9a-z]+$";  //***.***.***格式的域名，其中*为小写字母或数字；第一个括号代表有至少一个***.匹配单元，而[0-9a-z]$表明以小写字母或数字结尾；
        mailRegex = mailName + "@" + mailDomain;   //邮箱正则表达式 ^[0-9a-z]+\w*@([0-9a-z]+\.)+[0-9a-z]+$ 例：aa@123.com
        pattern = Pattern.compile(mailRegex); //通过complie方法返回一个pattern对象
        /**
         * 参数条件：
         * name：非空，限定16字符---
         * email：非空，唯一，合法邮箱
         * password：非空(只判断password)，至少6字符，限定16字符，判断二次输入是否相同(比较两次输入)，
         */
        if (name.equals("")) {//name 条件
            nameMsg.add("昵称 不能为空");
            errormsg.put("name", nameMsg);
        } else {
            if (name.length() >= 16) {
                nameMsg.add("昵称 不能超过16个字符");
                errormsg.put("name", nameMsg);
            } else {
                //name 格式正确
                nameBoo = true;
            }
        }
        if (email.equals("")) {//email 条件
            emailMsg.add("邮箱 不能为空");
            errormsg.put("email", emailMsg);
        } else {
            matcher = pattern.matcher(email);
            if (matcher.matches()) {
                //邮箱合法后排重，提示
                final HashMap<String, Object> emailMap = new HashMap<>();
                emailMap.put("email", email);
                final List<Users> users = usersMapper.selectByMap(emailMap);
                if (users.size() == 0) {
                    emailBoo = true;
                } else {
                    emailMsg.add("邮箱 已经存在");
                    errormsg.put("email", emailMsg);
                }
            } else {
                emailMsg.add("邮箱 不是一个合法的邮箱");
                errormsg.put("email", emailMsg);
            }
        }

        if (password.equals("")) {//password 条件
            passwordMsg.add("密码 不能为空");
            errormsg.put("password", passwordMsg);
        } else {
            if (password.length() < 6) {
                passwordMsg.add("密码 至少为 6 个字符");
            }
            if (password.length() >= 16) {
                passwordMsg.add("密码 不能大于 16 个字符");
            }
            if (password.equals(password_confirmation)) {
                //密码一致后注册操作
                passwordBoo = true;
            } else {
                passwordMsg.add("密码 两次输入不一致");
                errormsg.put("password", passwordMsg);
            }
        }


        if (nameBoo && emailBoo && passwordBoo) {
            String pw = MD5Handler.stringToMD5(password);
            final Users users = new Users();
            users.setName(name);
            users.setEmail(email);
            users.setPassword(pw);
            usersMapper.insert(users);
            return new ResponseEntity<>(null, HttpStatus.CREATED);
        } else {
            registerErrors.setMessage("The given data was invalid.");
            registerErrors.setErrors(errormsg);
            registerErrors.setStatus_code(422);
            return new ResponseEntity<>(registerErrors, HttpStatus.UNPROCESSABLE_ENTITY);
        }
    }

    /**
     * 刷新token
     * 前提--已经存在数据库中，没有被logout
     * 原理--判断该token是否过期，过期则返回error已失效，否则再判断数据库是否存在此token，
     * 没有则返回error已拉入黑名单，否则重新生成该用户token，存入该用户列表中
     *
     * @return
     */
    @ApiOperation("用户token刷新")
    @PostMapping("/auth/refresh")
    public ResponseEntity<Object> refresh() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        final String Authorization = request.getHeader("authorization");
        String[] tokens = Authorization.split(" ");
        String token = tokens[1];
        //未过期：false，过期：true
        if (isExpiration(token)) {
            final RegisterErrors registerErrors = new RegisterErrors();
            registerErrors.setMessage("Token Signature could not be verified.");
            registerErrors.setErrors("Token已失效");
            registerErrors.setStatus_code(401);
            return new ResponseEntity<>(registerErrors, HttpStatus.UNAUTHORIZED);
        } else {
            final HashMap<String, Object> tokenMap = new HashMap<>();
            tokenMap.put("remember_token", token);
            final List<Users> isToken = usersMapper.selectByMap(tokenMap);
            if (isToken.size() != 0) {
                final TokenVO tokenVO = new TokenVO();
                final String RToken = refreshToken(isToken.get(0).getEmail());//重新生成token
                UpdateWrapper<Users> updateWrapper = new UpdateWrapper<>();
                updateWrapper.eq("email", isToken.get(0).getEmail()).set("remember_token", RToken);
                usersMapper.update(null, updateWrapper);
                tokenVO.setAccess_token(RToken);
                tokenVO.setToken_type("Bearer");
                tokenVO.setExpires_in(360000);
                return new ResponseEntity<>(tokenVO, HttpStatus.OK);
            } else {
                final RegisterErrors registerErrors = new RegisterErrors();
                registerErrors.setMessage("The token has been blacklisted.");
                registerErrors.setErrors("Token已被列入黑名单");
                registerErrors.setStatus_code(401);
                return new ResponseEntity<>(registerErrors, HttpStatus.UNAUTHORIZED);
            }
        }
    }

    /**
     * 用户登录
     *
     * @param email    登录邮箱
     * @param password 登录密码
     * @return
     */
    @ApiOperation("用户登录")
    @PostMapping("/auth/login")
    public ResponseEntity<Object> login(@RequestParam String email, @RequestParam String password) {
        final RegisterErrors registerErrors = new RegisterErrors();
        final TokenVO tokenVO = new TokenVO();
        final HashMap<String, Object> errormsg = new HashMap<>();
        final ArrayList<Object> emailMsg = new ArrayList<>();
        final ArrayList<Object> passwordMsg = new ArrayList<>();

        Boolean emailBoo = false, passwordBoo = false; //必填条件判断状态
        String mailRegex, mailName, mailDomain;
        mailName = "^[0-9a-z]+\\w*";
        mailDomain = "([0-9a-z]+\\.)+[0-9a-z]+$";
        mailRegex = mailName + "@" + mailDomain;
        pattern = Pattern.compile(mailRegex);


        if (email.equals("")) {//email 条件
            emailMsg.add("邮箱 不能为空");
            errormsg.put("email", emailMsg);
        } else {
            matcher = pattern.matcher(email);
            if (matcher.matches()) {
                //邮箱合法后排重，提示
                final HashMap<String, Object> emailMap = new HashMap<>();
                emailMap.put("email", email);
                final List<Users> users = usersMapper.selectByMap(emailMap);
                System.out.println(users.size());
                if (users.size() != 0) {
                    emailBoo = true;
                } else {
                    emailMsg.add("邮箱 未注册");
                    errormsg.put("email", emailMsg);
                }
            } else {
                emailMsg.add("邮箱 不是一个合法的邮箱");
                errormsg.put("email", emailMsg);
            }
        }
        if (password.equals("")) {//password 条件
            passwordMsg.add("密码 不能为空");
            errormsg.put("password", passwordMsg);
        } else {
            if (password.length() < 6) {
                passwordMsg.add("密码 至少为 6 个字符");
                errormsg.put("password", passwordMsg);
            } else {
                if (password.length() >= 16) {
                    passwordMsg.add("密码 不能大于 16 个字符");
                    errormsg.put("password", passwordMsg);
                } else {
                    passwordBoo = true;
                }
            }
        }

        if (emailBoo && passwordBoo) {
            String pw = MD5Handler.stringToMD5(password);
            final HashMap<String, Object> emailVerifyMap = new HashMap<>();
            emailVerifyMap.put("email", email);
            emailVerifyMap.put("password", pw);//传入密码进行加密比对
            final List<Users> usersVerify = usersMapper.selectByMap(emailVerifyMap);
            if (usersVerify.size() == 0) {
                passwordMsg.add("密码 错误");
                errormsg.put("password", passwordMsg);
                registerErrors.setMessage("The given data was invalid.");
                registerErrors.setErrors(errormsg);
                registerErrors.setStatus_code(401);
                return new ResponseEntity<>(registerErrors, HttpStatus.UNAUTHORIZED);

            } else {
                //密码正确后返回token
                final String token = JWTUtil.generateToken(email);
                UpdateWrapper<Users> updateWrapper = new UpdateWrapper<>();
                updateWrapper.eq("email", email).set("remember_token", token);
                usersMapper.update(null, updateWrapper);
                tokenVO.setAccess_token(token);
                tokenVO.setToken_type("Bearer");
                tokenVO.setExpires_in(360000);
                return new ResponseEntity<>(tokenVO, HttpStatus.OK);

            }

        } else {
            registerErrors.setMessage("The given data was invalid.");
            registerErrors.setErrors(errormsg);
            registerErrors.setStatus_code(422);
            return new ResponseEntity<>(registerErrors, HttpStatus.UNPROCESSABLE_ENTITY);
        }
    }

    /**
     * 退出登录
     * 前提--判断传入token是否存在，没有则返回error已拉入黑名单，否则将该用户token清空
     *
     * @return
     */
    @ApiOperation("用户退出登录")
    @PostMapping("/auth/logout")
    public ResponseEntity<Object> logout() {
        //获取Authorization头部token
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        final String Authorization = request.getHeader("authorization");
        String[] tokens = Authorization.split(" ");
        String token = tokens[1];
        //销毁token操作
        final HashMap<String, Object> tokenMap = new HashMap<>();
        tokenMap.put("remember_token", token);
        final List<Users> isToken = usersMapper.selectByMap(tokenMap);
        if (isToken.size() != 0) {
            UpdateWrapper<Users> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("email", isToken.get(0).getEmail()).set("remember_token", null);
            usersMapper.update(null, updateWrapper);
            return new ResponseEntity<>(null, HttpStatus.NO_CONTENT);
        } else {
            final RegisterErrors registerErrors = new RegisterErrors();
            registerErrors.setMessage("The token has been blacklisted.");
            registerErrors.setErrors("Token已被列入黑名单");
            registerErrors.setStatus_code(401);
            return new ResponseEntity<>(registerErrors, HttpStatus.UNAUTHORIZED);
        }
    }

    /**
     * 用户头像上传
     *
     * @param file
     * @return
     * @throws Exception
     */
    @ApiOperation("用户头像上传")
    @PostMapping("/user/avatar")
    public ResponseEntity<Object> updateUserAvatar(@RequestParam("file") MultipartFile file) throws Exception {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        final String Authorization = request.getHeader("authorization");
        String[] tokens = Authorization.split(" ");
        String token = tokens[1];
        final HashMap<String, Object> tokenMap = new HashMap<>();
        tokenMap.put("remember_token", token);
        final List<Users> isToken = usersMapper.selectByMap(tokenMap);
        if (isToken.size() == 0) {
            final RegisterErrors registerErrors = new RegisterErrors();
            registerErrors.setMessage("The token has been blacklisted.");
            registerErrors.setErrors("Token已被列入黑名单");
            registerErrors.setStatus_code(401);
            return new ResponseEntity<>(registerErrors, HttpStatus.UNAUTHORIZED);
        } else {
            if (!isExpiration(token)) {//判断token有效期
                final HashMap<String, Object> result = new HashMap<>();
                if (!file.isEmpty()) {
                    // 获取文件名
                    String fileName = file.getOriginalFilename();
                    // 设置文件存储路径
                    String filePath = FileUtil.getUploadPath();
                    // String path = filePath + fileName + suffixName;
                    // 获取文件的后缀名
                    String suffixName = fileName.substring(fileName.lastIndexOf("."));

                    String avatar = isToken.get(0).getName() + suffixName;

                    final SimpleDateFormat sDateFormate = new SimpleDateFormat("yyyy-MM");  //设置时间格式
                    String nowTimeDir = sDateFormate.format(new Date());

                    String location = "http://" + request.getServerName() + ":" + request.getServerPort();
                    String relativePath = "/images/" + nowTimeDir + "/";
                    String url = location + relativePath + avatar;

                    try (BufferedOutputStream out = new BufferedOutputStream(
                            new FileOutputStream(new File(filePath + File.separator + avatar)))) {
                        out.write(file.getBytes());
                        out.flush();

                        //修改对应用户头像地址
                        UpdateWrapper<Users> updateWrapper = new UpdateWrapper<>();
                        updateWrapper.eq("id", isToken.get(0).getId())
                                .eq("email", isToken.get(0).getEmail())
                                .set("avatar_url", url)
                                .set("avatar", avatar);
                        usersMapper.update(null, updateWrapper);

                        result.put("data", "上传成功");
                        return new ResponseEntity<>(result, HttpStatus.NO_CONTENT);
                    } catch (FileNotFoundException e) {
                        result.put("data", "上传失败");
                        return new ResponseEntity<>(result, HttpStatus.BAD_REQUEST);
                    } catch (IOException e) {
                        result.put("data", "上传失败");
                        return new ResponseEntity<>(result, HttpStatus.BAD_REQUEST);
                    }
                } else {
                    result.put("data", "上传文件失败，文件为空");
                    return new ResponseEntity<>(result, HttpStatus.BAD_REQUEST);
                }


            } else {
                final RegisterErrors registerErrors = new RegisterErrors();
                registerErrors.setMessage("Token Signature could not be verified.");
                registerErrors.setErrors("Token已失效");
                registerErrors.setStatus_code(401);
                return new ResponseEntity<>(registerErrors, HttpStatus.UNAUTHORIZED);
            }
        }
    }
}
